﻿using System;
using System.Linq.Expressions;
using CoreEx.Database.Query.Expressions;
using CoreEx.DynamicInvoker;
using LinFu.IoC.Configuration;

namespace CoreEx.Database.Linq.Implementation.ExpressionHandlers
{
    /// <summary>
    /// Translates a <see cref="BinaryExpression"/> into a <see cref="DbBinaryExpression"/>.
    /// </summary>
    [Implements(typeof(IExpressionHandler<BinaryExpression>))]
    public class BinaryExpressionHandler : ExpressionHandlerBase<BinaryExpression>
    {
         /// <summary>
        /// Translates the <paramref name="expression"/> into a <see cref="DbBinaryExpression"/> instance.
        /// </summary>
        /// <param name="expression">The <see cref="BinaryExpression"/>to translate.</param>        
        /// <example>
        /// The following example shows a lambda expression with an equals binary expression.<br/><br/>
        /// <b>Lambda Expression</b>
        /// <code>
        /// <![CDATA[table.Where(c => c.CustomerID == "ALFKI");]]>
        /// </code>
        /// <b>SQL</b>
        /// <code>
        /// <![CDATA[WHERE ([t0].[CustomerID] = @p0)]]>
        /// </code>
        /// </example>
        /// <returns><see cref="DbBinaryExpression"/></returns>
        public override DbExpression HandleExpression(BinaryExpression expression, Func<Expression, DbExpression> visit)
        {
             var factoryMethodName = GetFactoryMethodName(expression.NodeType);
            var dbExpression = (DbExpression)typeof(DbExpressionFactory).DynamicInvoke(ExpressionFactory,
                                                                                         factoryMethodName,
                                                                                         visit(expression.Left),
                                                                                         visit(expression.Right));
            return dbExpression;
            }

        /// <summary>
        /// Gets the name of the factory method to be invoked on the <see cref="DbExpressionFactory"/> instance.
        /// </summary>
        /// <param name="expressionType">The type of <see cref="Expression"/> currently being translated.</param>
        /// <returns><see cref="string"/></returns>
        /// <remarks>
        /// Since the factory method names corresponds to the <see cref="ExpressionType"/> enumeration 
        /// we can just dynamically invoke the factory method based on the enumeration value.
        /// </remarks>
        private static string GetFactoryMethodName(ExpressionType expressionType)
        {
            if (expressionType == ExpressionType.OrElse)
                expressionType = ExpressionType.Or;
            if (expressionType == ExpressionType.AndAlso)
                expressionType = ExpressionType.Or;
            return Enum.GetName(typeof(ExpressionType), expressionType);
        }        
    }
}
